
import pygame
from OpenGL.GL import *
from OpenGL.GLU import *

class GUI:
    """A basic GUI system for Ouden
    
    Dependencies: pygame, PyOpenGL
    """
    def __init__(self, engine):
        self.root = GUI.Widget(parent=None, name="root")
        # TODO: Replace these!
        #engine.addEventListener('input', self.root.handleOSEvent)
        #engine.addEventListener('renderGUI', self.root.render)
        '''engine.appendEventHandler('key', self.root.handleKeyEvent)
        engine.appendEventHandler('mouse_button', \
                                  self.root.handleMouseButtonEvent)
        engine.appendEventHandler('mouse_motion', \
                                  self.root.handleMouseMotionEvent)'''
        
    class Widget:
        class __Event:
            def __init__(self, name, *args):
                self.name = name
                self.args = args
        def __init__(self, parent, name, pos=(0, 0), size=(0.1, 0.1)):
            self.parent = parent
            self.name = name
            if self.parent is not None:
                self.parent.addChild(self)
            # Note: Children are kept in order of bottom-most to top-most
            self.children = []
            self.events = []
            self.pos = pos
            self.size = size
            self.rect = (self.pos[0]-self.size[0]*0.5, \
                         self.pos[0]+self.size[0]*0.5, \
                         self.pos[1]-self.size[1]*0.5, \
                         self.pos[1]+self.size[1]*0.5)
        def addChild(self, newChild):
            self.children.append(newChild)
        #def addEvent(self, name, *args):
        #    self.events[name] = Event(name, *args)
        def handleKeyEvent(self, action, key, modifiers):
            # TODO: Replace this with proper focus handling
            for child in self.children:
                child.handleKeyEvent(action, key, modifiers)
            return True
        def handleMouseButtonEvent(self, action, button, world_pos, gui_pos):
            # Iterate from top-most child to bottom-most
            for child in reversed(self.children):
                if gui_pos[0] > child.rect[0] and \
                   gui_pos[0] < child.rect[1] and \
                   gui_pos[1] > child.rect[2] and \
                   gui_pos[1] < child.rect[3]:
                    # Let the child decide whether to handle the event
                    if not child.handleMouseButtonEvent(button, world_pos, \
                                                        gui_pos):
                        return False
            return True
        def handleMouseMotionEvent(self, buttons, world_pos, gui_pos, rel):
            # Iterate from top-most child to bottom-most
            for child in reversed(self.children):
                if gui_pos[0] > child.rect[0] and \
                   gui_pos[0] < child.rect[1] and \
                   gui_pos[1] > child.rect[2] and \
                   gui_pos[1] < child.rect[3]:
                    # Let the child decide whether to handle the event
                    if not child.handleMouseMotionEvent(buttons, world_pos, \
                                                        gui_pos, rel):
                        return False
            return True
        """def handleOSEvent(self, engine, event):
            # TODO: Work out how to determine mouseEnter and mouseLeave events
            # Pass all mouse events to children under the mouse position
            if event.type == pygame.MOUSEMOTION or \
               event.type == pygame.MOUSEBUTTONUP or \
               event.type == pygame.MOUSEBUTTONDOWN:
                # Iterate from top-most child to bottom-most
                for child in reversed(self.children):
                    pos = engine.convertPxlsToGUICoords(event.pos)
                    if pos[0] > child.rect[0] and \
                       pos[0] < child.rect[1] and \
                       pos[1] > child.rect[2] and \
                       pos[1] < child.rect[3]:
                        child.handleOSEvent(engine, event)
                        # And break so that only the top-most child receives the event
                        break
            elif event.type == pygame.KEYDOWN or \
               event.type == pygame.KEYUP:
                for child in self.children:
                    child.handleOSEvent(engine, event)
        """
        def raiseEvent(self, name, *args, **kwargs):
            callbackName = self.name + '_' + name
            # If no callback has been defined for this event then it is ignored
            if hasattr(self.parent, callbackName):
                getattr(self.parent, callbackName)(*args, **kwargs)
        #def update(self, timeStep):
        #    for child in children:
        #        child.update(timeStep)
        def render(self, engine):
            for child in self.children:
                child.render(engine)
        def bringToFront(self):
            self.parent.children.remove(self)
            self.parent.children.append(self)
        def sendToBack(self):
            self.parent.children.remove(self)
            self.parent.children.insert(0, self)
        def bringForward(self):
            c = self.parent.children
            i = c.index(self)
            if i is not len(c)-1:
                c[i], c[i+1] = c[i+1], c[i]
        def sendBackward(self):
            c = self.parent.children
            i = c.index(self)
            if i is not 0:
                c[i-1], c[i] = c[i], c[i-1]
    
    class Frame(Widget):
        def __init__(self, parent, name, pos=(0, 0), size=(2.0, 2.0)):
            GUI.Widget.__init__(self, parent, name, pos, size)
        
    class Button(Widget):
        def __init__(self, engine, parent, name, pos, size=(0.2, 0.1)):
            GUI.Widget.__init__(self, parent, name, pos, size)
            self.texture = engine.renderer.textureLoader.getTexture("button1")
            self.texture.isOnLoop = False
            self.texture.frameRate = 40
        def handleMouseButtonEvent(self, action, button, world_pos, gui_pos):
            if action == 'down':
                # TODO: Check why this is here or where it should be
                #self.texture.startAnimating(engine)
                self.raiseEvent("Click", pos=pos, button=button)
        def handleMouseMotionEvent(self, buttons, world_pos, gui_pos, rel):
            self.raiseEvent("MouseMove", pos=pos)
            # TODO: Add more events here
        def render(self, engine):
            glPushMatrix()
            glTranslatef(self.pos[0], self.pos[1], 0)
            glScalef(self.size[0], self.size[1], 1)
            self.texture.bind()
            glColor4f(1, 1, 1, 1)
            #glColor4f(0.9, 0.4, 0.0, 1.0)
            #if self.active:
            #    glColor4f(self.color[0], self.color[1], self.color[2], self.color[3])
            #else:
            #    glColor4f(0, 0.6, self.color[2], self.color[3])
            glBegin(GL_QUADS)
            glTexCoord2f(0, 0)
            glVertex2f(-0.5, -0.5)
            glTexCoord2f(1, 0)
            glVertex2f(0.5, -0.5)
            #glColor4f(0.9, 0.6, 0.0, 1.0)
            glTexCoord2f(1, 1)
            glVertex2f(0.5, 0.5)
            glTexCoord2f(0, 1)
            glVertex2f(-0.5, 0.5)
            glEnd()
            glPopMatrix()
            # TODO: Do we actually need to consider children of a button?
            # Render children from back-most to front-most
            for child in self.children:
                child.render(engine)
                
    class CheckBox(Widget):
        def __init__(self, engine, parent, name, pos, size=(0.05, 0.05)):
            GUI.Widget.__init__(self, parent, name, pos, size)
            self.texture = engine.renderer.textureLoader.getTexture("None")
            #self.texture.isOnLoop = False
            #self.texture.frameRate = 25
            
            self.isChecked = False
            
        def handleMouseButtonEvent(self, action, button, world_pos, gui_pos):
            if action == 'down':
                self.isChecked = not self.isChecked
                self.raiseEvent("Click", pos=pos, button=button)
        def render(self, engine):
            glPushMatrix()
            glTranslatef(self.pos[0], self.pos[1], 0)
            glScalef(self.size[0], self.size[1], 1)
            self.texture.bind()
            glColor4f(1, 1, 1, 1)
            # Render a box
            glBegin(GL_QUADS)
            glTexCoord2f(0, 0)
            glVertex2f(-0.5, -0.5)
            glTexCoord2f(1, 0)
            glVertex2f(0.5, -0.5)
            glTexCoord2f(1, 1)
            glVertex2f(0.5, 0.5)
            glTexCoord2f(0, 1)
            glVertex2f(-0.5, 0.5)
            glEnd()
            if self.isChecked:
                # Render the check mark
                self.texture.unbind()
                glColor4f(0.2, 0.2, 0.2, 1)
                glBegin(GL_LINES)
                glVertex2f(-0.5, -0.5)
                glVertex2f(0.5, 0.5)
                glVertex2f(0.5, -0.5)
                glVertex2f(-0.5, 0.5)
                glEnd()
            glPopMatrix()
            # Render children from back-most to front-most
            for child in self.children:
                child.render(engine)
                
"""
class GUI:
    class Button:
        def __init__(self, callback, pos, size=(0.2, 0.08), color=(0.6,0.3,0.8,0.8)):
            self.callback = callback
            self.pos, self.size, self.color = pos, size, color
            # Xmin, Xmax, Ymin, Ymax
            self.rect = (self.pos[0]-self.size[0]*0.5, \
                         self.pos[0]+self.size[0]*0.5, \
                         self.pos[1]-self.size[1]*0.5, \
                         self.pos[1]+self.size[1]*0.5)
            self.active = False
        def render(self):
            glPushMatrix()
            glTranslatef(self.pos[0], self.pos[1], 0)
            glScalef(self.size[0], self.size[1], 1)
            glBindTexture(GL_TEXTURE_2D, 0)
            if self.active:
                glColor4f(self.color[0], self.color[1], self.color[2], self.color[3])
            else:
                glColor4f(0, 0.6, self.color[2], self.color[3])
            glBegin(GL_QUADS)
            glVertex2f(-0.5, -0.5)
            glVertex2f(0.5, -0.5)
            glVertex2f(0.5, 0.5)
            glVertex2f(-0.5, 0.5)
            glEnd()
            glPopMatrix()
        
    def __init__(self, engine):
        engine.addEventListener('input', self.onInput)
        engine.addEventListener('tick', self.onTick)
        engine.addEventListener('renderGUI', self.onRender)
        
        self.items = []
        self.items.append(GUI.Button(self.onButton, (-0.9, 0.0)))
        self.items.append(GUI.Button(self.onButton, (-0.9, -0.1)))
        self.items.append(GUI.Button(self.onButton, (-0.9, 0.1)))
    def onInput(self, engine, event):
        if event.type == pygame.MOUSEBUTTONDOWN:
            pass
    def onTick(self, engine, timeStep):
        pos = engine.convertPxlsToGUICoords(engine.input.getMousePos())
        if pos[0] > self.items[0].rect[0] and \
           pos[0] < self.items[0].rect[1] and \
           pos[1] > self.items[0].rect[2] and \
           pos[1] < self.items[0].rect[3]:
            self.items[0].active = True
        else:
            self.items[0].active = False
        pass
    def onRender(self, engine):
        for item in self.items:
            item.render()
        pos = engine.convertPxlsToGUICoords(engine.input.getMousePos())
        glBegin(GL_TRIANGLES)
        glVertex3f(pos[0], pos[1], 0)
        glVertex3f(pos[0]-0.02, pos[1]-0.05, 0)
        glVertex3f(pos[0]+0.02, pos[1]-0.05, 0)
        glEnd()
            
    def onButton(self):
        print "Button pressed"
""" 
